// Water Geometry Shader

#include "WaterUtils.hlsl"

// Matrix Buffer
cbuffer MatrixBuffer : register(b0)
{
	row_major float4x4 World			: WORLD;
	row_major float4x4 WorldViewProj	: WORLDVIEWPROJECTION;
	row_major float4x4 View				: VIEW;
};

// Geometry Shader Input
struct GSInput
{
	float4 Position		: POSITION;
	float3 Normal		: NORMAL;
	float2 TexCoord		: TEXCOORD0;
};

// Geometry Shader Output
struct GSOutput
{
	float4 Position			: SV_POSITION;
	float4 WorldPosition	: WORLDPOSITION;
	float3 Normal			: NORMAL;
	float2 TexCoord			: TEXCOORD0;
	float2 Delta			: TEXCOORD1;
};

// Apply the Shader to a Vertex
GSInput ApplyVertex(GSInput input, float2 delta)
{
	input.Position = CalculateHeight(input.Position);
	input.Normal = CalculateNormal(input.Position, delta);
	return input;
}

// Transform a Vertex into the Output Format
GSOutput TransformVertex(GSInput input)
{
	GSOutput output = (GSOutput)0;

	output.Position = mul(input.Position, WorldViewProj);
	output.WorldPosition = mul(input.Position, World);
	output.Normal = normalize(mul(input.Normal, (float3x3) World));
	output.TexCoord = input.TexCoord;

	return output;
}

#define VertexCount 3
[maxvertexcount(VertexCount)]
void main(triangle GSInput input[VertexCount], inout TriangleStream<GSOutput> output)
{
	// Calculate the Delta
	float2 delta = float2(0.0f, 0.0f);
	delta.x = (abs(input[1].Position.x - input[2].Position.x) + abs(input[1].Position.x - input[0].Position.x) + abs(input[2].Position.x - input[0].Position.x)) / 2.0f;
	delta.y = (abs(input[1].Position.z - input[2].Position.z) + abs(input[1].Position.z - input[0].Position.z) + abs(input[2].Position.z - input[0].Position.z)) / 2.0f;

	// Apply the Input Vertices
	GSInput vin[VertexCount] = input;
	for (uint i = 0; i < VertexCount; ++i)
		vin[i] = ApplyVertex(input[i], delta);

	// Transform the vertices
	for (uint g = 0; g < VertexCount; ++g)
	{
		GSOutput vout = TransformVertex(vin[g]);
		output.Append(vout);
	}

	output.RestartStrip();
}